#include "BookingClass.h"

BookingClass::BookingClass()
{
}

BookingClass::BookingClass(DataStore* input)
{
    link(input);
}

BookingClass::~BookingClass()
{
}

void BookingClass::link(DataStore* input)
{
    ds = input;
}

void BookingClass::makeBooking(int clientID)
{
    // Prepares non-client entry data
    bookStruct temp;

    srand(time(NULL));
    int generate;
    bool isValid = false;
    do
    {
        generate = rand() % 9999 + 1;
        if (!ds->findBookRef(generate))
        {
            isValid = true;
            temp.ref = generate;
        }
    }
    while (isValid == false);
    temp.bookDate = "13Feb2014";
    temp.status = (bookingStatus) 0;
    temp.clientID = clientID;

    // Takes in user input, quits if user enters any colon
    try
    {
        string userInput;
        cout << "Please do not enter any colons (:). ";
        cout << "Doing so will cause the form to be discarded" << endl << endl;
        cout << "Enter your name. Title - Surname - First Name format preferred: " << endl;
        userInput.clear();
        getline(cin, userInput, '\n');
        if (ds->hasColon(userInput)) throw 1;
        temp.name = userInput;

        cout << endl << "Enter your full address. Street - Town - City - Postcode format preferred:" << endl;
        userInput.clear();
        getline(cin, userInput, '\n');
        if (ds->hasColon(userInput)) throw 1;
        temp.address = userInput;

        isValid = false;
        do
        {
            cout << endl << "List of holiday packages available as follows." << endl << endl;
            listPackages();
            cout << endl << "Enter the code of the holiday package you wish to take: ";
            int input;
            cin >> input;
            cin.clear();
            cin.ignore(INT_MAX, '\n');
            if (ds->findHolCode(input))
            {
                isValid = true;
                temp.code = input;
                temp.destination = ds->holidays[(ds->findHolCode(input) - 1)].destination;
                temp.type = ds->holidays[(ds->findHolCode(input) - 1)].type;
            }
            else
                cout << endl << "Invalid code. Please redo." << endl;
        }
        while (isValid == false);

        cout << endl << "Enter your preferred start and end dates in Date - Month - Year format." << endl;
        cout << "Starting Date: ";
        userInput.clear();
        getline(cin, userInput, '\n');
        if (ds->hasColon(userInput)) throw 1;
        temp.startDate1 = userInput;

        cout << "Ending Date: ";
        userInput.clear();
        getline(cin, userInput, '\n');
        if (ds->hasColon(userInput)) throw 1;
        temp.endDate1 = userInput;

        cout << endl << "Enter your second choices for start and end Dates. Enter \"none\" if not needed." << endl;
        cout << "Starting Date: ";
        userInput.clear();
        getline(cin, userInput, '\n');
        if (ds->hasColon(userInput)) throw 1;
        temp.startDate2 = userInput;

        cout << "Ending Date: ";
        userInput.clear();
        getline(cin, userInput, '\n');
        if (ds->hasColon(userInput)) throw 1;
        temp.endDate2 = userInput;

        cout << endl << "Enter any special requirements you may have:" << endl;
        userInput.clear();
        getline(cin, userInput, '\n');
        if (ds->hasColon(userInput)) throw 1;
        temp.special = userInput;

        ds->bookings.push_back(temp);
        cout << endl << "Booking successfully made." << endl;
    }
    catch (int e)
    {
        cout << "Input field contains a colon! Booking form has been discarded." << endl;
    }
}

void BookingClass::editAndCancelBooking(int clientID)
{
    // Print bookings related to the client
    int input;
    bool isValid = false;
    do
    {
        cout << "List of your bookings as follows." << endl << endl;
        printBookingList(ds->listClientBookings(clientID));
        cout << "Enter the reference number of the booking you wish to edit or cancel: ";

        cin >> input;
        cin.clear();
        cin.ignore(INT_MAX, '\n');

        if (ds->findBookRef(input))
            isValid = true;
        else
        {
            cout << endl << "Invalid reference number. Please redo." << endl << endl;
        }
    }
    while (isValid == false);

    cout << endl << "You have entered reference number: " << input << endl;
    int indexNo = ds->findBookRef(input) - 1;


    // Submenu for client to change details
    bool hasExit = false;
    do
    {
        cout << endl << "The fields you can modify are:" << endl << endl
                << "1. Name" << endl
                << "2. Address" << endl
                << "3. Destination Code" << endl
                << "4. Start Date #1" << endl
                << "5. End Date #1" << endl
                << "6. Start Date #2" << endl
                << "7. End Date #2" << endl
                << "8. Special Requirements" << endl
                << "9. Cancel this booking" << endl << endl
                << "Please enter an option (10 to stop editing): ";

        int input;
        cin >> input;
        cin.clear();
        cin.ignore(INT_MAX, '\n');
        cout << endl;

        try
        {
            int test;
            string userInput;
            switch (input)
            {
            case 1: cout << "New name: ";
                userInput.clear();
                getline(cin, userInput, '\n');
                if (ds->hasColon(userInput)) throw 1;
                ds->bookings[indexNo].name = userInput;
                cout << "Done." << endl;
                ds->bookings[indexNo].status = Edited;
                break;

            case 2: cout << "New address: ";
                userInput.clear();
                getline(cin, userInput, '\n');
                if (ds->hasColon(userInput)) throw 1;
                ds->bookings[indexNo].address = userInput;
                cout << "Done." << endl;
                ds->bookings[indexNo].status = Edited;
                break;

            case 3:
            {
                bool holExist = false;
                do
                {
                    cout << endl << "List of holiday packages available as follows." << endl << endl;
                    listPackages();
                    cout << endl << "Enter the code of the holiday package you wish to take: ";
                    int which;
                    cin >> which;
                    cin.clear();
                    cin.ignore(INT_MAX, '\n');
                    if (ds->findHolCode(which))
                    {
                        holExist = true;
                        ds->bookings[indexNo].code = which;
                        ds->bookings[indexNo].destination = ds->holidays[(ds->findHolCode(which) - 1)].destination;
                        ds->bookings[indexNo].type = ds->holidays[(ds->findHolCode(which) - 1)].type;
                    }
                    else
                        cout << endl << "Invalid code. Please redo." << endl;
                }
                while (holExist == false);
                cout << "Done." << endl;
                ds->bookings[indexNo].status = Edited;
                break;
            }
            case 4: cout << "New Start Date #1: ";
                userInput.clear();
                getline(cin, userInput, '\n');
                if (ds->hasColon(userInput)) throw 1;
                ds->bookings[indexNo].startDate1 = userInput;
                cout << "Done." << endl;
                ds->bookings[indexNo].status = Edited;
                break;

            case 5: cout << "New End Date #1: ";
                userInput.clear();
                getline(cin, userInput, '\n');
                if (ds->hasColon(userInput)) throw 1;
                ds->bookings[indexNo].endDate1 = userInput;
                cout << "Done." << endl;
                ds->bookings[indexNo].status = Edited;
                break;

            case 6: cout << "New Start Date #2: ";
                userInput.clear();
                getline(cin, userInput, '\n');
                if (ds->hasColon(userInput)) throw 1;
                ds->bookings[indexNo].startDate2 = userInput;
                cout << "Done." << endl;
                ds->bookings[indexNo].status = Edited;
                break;

            case 7: cout << "New End Date #2: ";
                userInput.clear();
                getline(cin, userInput, '\n');
                if (ds->hasColon(userInput)) throw 1;
                ds->bookings[indexNo].endDate2 = userInput;
                cout << "Done." << endl;
                ds->bookings[indexNo].status = Edited;
                break;

            case 8: cout << "New Special Requirements: ";
                userInput.clear();
                getline(cin, userInput, '\n');
                if (ds->hasColon(userInput)) throw 1;
                ds->bookings[indexNo].special = userInput;
                cout << "Done." << endl;
                ds->bookings[indexNo].status = Edited;
                break;

            case 9: ds->bookings[indexNo].status = Cancelled;
                cout << "Booking has been cancelled. Editing will now cease." << endl;

            case 10: hasExit = true;
                break;

            default: break;
            }
        }
        catch (int e)
        {
            cout << "Input field contains a colon!" << endl << endl;
        }
    }
    while (hasExit == false);
}

void BookingClass::checkNewEditedBookings()
{
    int input;
    bool isValid = false;
    do
    {
        cout << "New and Edited bookings:" << endl << endl;
        listNewEditedBookings();
        cout << "Enter a reference number to change status of: ";

        cin >> input;
        cin.clear();
        cin.ignore(INT_MAX, '\n');

        if (ds->findBookRef(input))
            isValid = true;
        else
        {
            cout << endl << "Invalid reference number. Please redo." << endl << endl;
        }
    }
    while (isValid == false);

    cout << endl << "You have entered reference number: " << input << endl;
    int indexNo = ds->findBookRef(input) - 1;

    bool hasExit = false;
    do
    {
        cout << endl << "What would you like to do to this booking?" << endl << endl
                << "1. Mark as Incomplete" << endl
                << "2. Mark as Invalid" << endl
                << "3. Mark as Checked" << endl
                << "4. Leave Unchanged" << endl << endl
                << "Please enter an option: ";

        cin >> input;
        cin.clear();
        cin.ignore(INT_MAX, '\n');
        cout << endl;

        switch (input)
        {
        case 1: ds->bookings[indexNo].status = Incomplete;
            cout << "Marked as Incomplete." << endl;
            hasExit = true;
            break;
        case 2: ds->bookings[indexNo].status = Invalid;
            cout << "Marked as Invalid." << endl;
            hasExit = true;
            break;
        case 3: ds->bookings[indexNo].status = Checked;
            cout << "Marked as Checked." << endl;
            hasExit = true;
            break;
        case 4: cout << "Status Unchanged" << endl;
            hasExit = true;
            break;
        default: cout << "Please enter option 1-4 only." << endl;
            break;
        }
    }
    while (hasExit == false);
}

void BookingClass::checkCheckedBookings(int managerID)
{
    int input;
    bool isValid = false;
    do
    {
        cout << "Already checked bookings. Only bookings managed by you will be displayed." << endl << endl;
        listCheckedBookings(managerID);
        cout << "Enter a reference number to change status of: ";

        cin >> input;
        cin.clear();
        cin.ignore(INT_MAX, '\n');

        if (ds->findBookRef(input))
            isValid = true;
        else
        {
            cout << endl << "Invalid reference number. Please redo." << endl << endl;
        }
    }
    while (isValid == false);

    cout << endl << "You have entered reference number: " << input << endl;
    int indexNo = ds->findBookRef(input) - 1;

    bool hasExit = false;
    do
    {
        cout << endl << "What would you like to do to this booking?" << endl << endl
                << "1. Mark as on Waiting List" << endl
                << "2. Mark as Payment Required" << endl
                << "3. Leave Unchanged" << endl << endl
                << "Please enter an option: ";

        cin >> input;
        cin.clear();
        cin.ignore(INT_MAX, '\n');
        cout << endl;

        switch (input)
        {
        case 1: ds->bookings[indexNo].status = Waitlist;
            cout << "Marked as on Waiting List." << endl;
            hasExit = true;
            break;
        case 2: ds->bookings[indexNo].status = Payment;
            cout << "Marked as Payment Required." << endl;
            hasExit = true;
            break;
        case 3: cout << "Status Unchanged" << endl;
            hasExit = true;
            break;
        default: cout << "Please enter option 1-3 only." << endl;
            break;
        }
    }
    while (hasExit == false);
}

void BookingClass::checkApprovedBookings()
{
    int input;
    bool isValid = false;
    do
    {
        cout << "Bookings approved by Holiday Managers:" << endl << endl;
        listApprovedBookings();
        cout << "Enter a reference number to change status of: ";

        cin >> input;
        cin.clear();
        cin.ignore(INT_MAX, '\n');

        if (ds->findBookRef(input))
            isValid = true;
        else
        {
            cout << endl << "Invalid reference number. Please redo." << endl << endl;
        }
    }
    while (isValid == false);

    cout << endl << "You have entered reference number: " << input << endl;
    int indexNo = ds->findBookRef(input) - 1;

    bool hasExit = false;
    do
    {
        cout << endl << "What would you like to do to this booking?" << endl << endl
                << "1. Mark as Confirmed" << endl
                << "2. Mark as Cancelled" << endl
                << "3. Leave Unchanged" << endl << endl
                << "Please enter an option: ";

        cin >> input;
        cin.clear();
        cin.ignore(INT_MAX, '\n');
        cout << endl;

        switch (input)
        {
        case 1: ds->bookings[indexNo].status = Confirmed;
            cout << "Marked as Confirmed." << endl;
            hasExit = true;
            break;
        case 2: ds->bookings[indexNo].status = Cancelled;
            cout << "Marked as Cancelled." << endl;
            hasExit = true;
            break;
        case 3: cout << "Status Unchanged" << endl;
            hasExit = true;
            break;
        default: cout << "Please enter option 1-3 only." << endl;
            break;
        }
    }
    while (hasExit == false);
}

void BookingClass::checkCancelledBookings()
{
    int input;
    bool isValid = false;
    do
    {
        cout << "Bookings cancelled by customers or the Finance Office:" << endl << endl;
        listCancelledBookings();
        cout << "Enter a reference number: ";

        cin >> input;
        cin.clear();
        cin.ignore(INT_MAX, '\n');

        if (ds->findBookRef(input))
            isValid = true;
        else
        {
            cout << endl << "Invalid reference number. Please redo." << endl << endl;
        }
    }
    while (isValid == false);

    cout << endl << "You have entered reference number: " << input << endl;
    int indexNo = ds->findBookRef(input) - 1;

    bool hasExit = false;
    do
    {
        cout << endl << "What would you like to do to this booking?" << endl << endl
                << "1. Send message to the client" << endl
                << "2. Leave Unchanged" << endl << endl
                << "Please enter an option: ";

        cin >> input;
        cin.clear();
        cin.ignore(INT_MAX, '\n');
        cout << endl;

        switch (input)
        {
        case 1: cout << "Message Sent." << endl;
            hasExit = true;
            break;
        case 2: cout << "Status Unchanged" << endl;
            hasExit = true;
            break;
        default: cout << "Please enter option 1-2 only." << endl;
            break;
        }
    }
    while (hasExit == false);
}

void BookingClass::listNewEditedBookings()
{
    deque<bookStruct> temp;
    int size = ds->bookings.size();
    for (int i = 0; i < size; i++)
    {
        if (ds->bookings[i].status == New || ds->bookings[i].status == Edited)
        {
            temp.push_back(ds->bookings[i]);
        }
    }
    printBookingList(temp);
}

void BookingClass::listCheckedBookings(int managerID)
{
    deque<bookStruct> temp;
    int size = ds->bookings.size();
    for (int i = 0; i < size; i++)
    {
        if (ds->bookings[i].status == Checked)
        {
            int index = ((ds->findHolCode(ds->bookings[i].code)) - 1);
            if (ds->holidays[index].managerID == managerID)
                temp.push_back(ds->bookings[i]);
        }
    }
    printBookingList(temp);
}

void BookingClass::listApprovedBookings()
{
    deque<bookStruct> temp;
    int size = ds->bookings.size();
    for (int i = 0; i < size; i++)
    {
        if (ds->bookings[i].status == Payment)
        {
            temp.push_back(ds->bookings[i]);
        }
    }
    printBookingList(temp);
}

void BookingClass::listCancelledBookings()
{
    deque<bookStruct> temp;
    int size = ds->bookings.size();
    for (int i = 0; i < size; i++)
    {
        if (ds->bookings[i].status == Cancelled)
        {
            temp.push_back(ds->bookings[i]);
        }
    }
    printBookingList(temp);
}

void BookingClass::listPackages()
{
    int size = ds->holidays.size();

    cout << left << setw(12) << "PackageId"
            << left << setw(45) << "Destination"
            << left << setw(15) << "Type"
            << endl;

    cout << setw(72) << setfill('-') << "-" << endl;
    cout << setfill(' ');

    for (int i = 0; i < size; ++i)
    {
        cout << left << setw(12) << ds->holidays[i].code
                << left << setw(45) << ds->holidays[i].destination
                << left << setw(15) << ds->holidays[i].type
                << endl;
    }
}

void BookingClass::printBookingList(deque<bookStruct> list)
{
    int size = list.size();
    for (int i = 0; i < size; i++)
    {
        cout << "Reference Number: " << list[i].ref << endl
                << "Name: " << list[i].name << endl
                << "Address: " << list[i].address << endl
                << "Holiday Code: " << list[i].code << endl
                << "Holiday Destination: " << list[i].destination << endl
                << "Holiday Type: " << ds->holidayString(list[i].type) << endl
                << "Start and End dates (Set 1): " << list[i].startDate1
                << " - " << list[i].endDate1 << endl
                << "Start and End dates (Set 2): " << list[i].startDate2
                << " - " << list[i].endDate2 << endl
                << "Special Requirements: " << list[i].special << endl
                << "Date of booking: " << list[i].bookDate << endl
                << "Booking Status: " << ds->bookingString(list[i].status) << endl
                << "Client's ID: " << list[i].clientID << endl << endl;
    }
}